var colors = require('colors');
var httpProxy = require('http-proxy');
var proxyServer = httpProxy.createProxyServer({});
var moment = require('moment');
var logger = require('tracer').colorConsole();
var request = require('request');

var url = require('url');
var formidable = require('formidable');

// To modify the proxy connection before data is sent, you can listen 
// for the 'proxyReq' event. When the event is fired, you will receive 
// the following arguments: 
// (http.ClientRequest proxyReq, http.IncomingMessage req, 
//  http.ServerResponse res, Object options). This mechanism is useful when 
// you need to modify the proxy request before the proxy connection 
// is made to the target. 
// 
// proxyServer.on('proxyReq', function(proxyReq, req, res, options) {
//   // proxyReq.setHeader('X-Special-Proxy-Header', 'foobar');
// });

// 
// Listen for the `proxyRes` event on `proxy`. 
// 
proxyServer.on('proxyRes', function(proxyRes, req, res) {

  if (0) {
    delete proxyRes.headers['etag']
    delete proxyRes.headers['last-modified']
      //以上要个要全部不存在才有效

    res.setHeader('X-Special-Proxy-Header', 'water7melon');

    res.setHeader('Cache-Control', 'private, max-age=0, no-cache');
    res.setHeader('Pragma', 'no-cache');
    // 以上两个也没有什么卵用, 但是微信端需要有才有效
    res.setHeader('Expires', 'Mon, 26 Jul 1970 05:00:00 GMT'); //并没有什么卵用,没有的话微信端会加载很慢
  }
});

proxyServer.on('error', function (err, req, res) {
  logger.error(err)
});

var util = {
  proxylog: function(req, res, target) {
    console.log('[%s] "%s %s %s %s %s %s" "%s"', moment().format('YYYY-MM-DD HH:mm:ss,SSSZ'),
      req.method.green,
      req.url.yellow.bold,
      'pass'.green,
      req.headers.host.yellow.bold,
      'to'.green,
      target.yellow.bold,
      req.headers['user-agent']
    );
  },
  formParse: function(req, cb) {
    req.pipe(process.stdin);

    var form = new formidable.IncomingForm();
    form.parse(req, function(err, fields, files) {
      cb(err, fields, files);
    });
  },
  proxyMultiPartForm: function(req, res, target) {
    util.proxylog(req, res, target || 'http://127.0.0.1');
    try {
      proxyServer.web(req, res, {
        target: target || 'http://127.0.0.1',
        secure: true
      });
    } catch (e) {
      logger.log(e);
    }
  },
  proxy: function(req, res, target) {
    util.proxylog(req, res, target || 'http://127.0.0.1');
    // try {
    //   proxyServer.web(req, res, {
    //     target: target || 'http://127.0.0.1',
    //     secure: true
    //   });
    // } catch (e) {
    //   logger.log(e);
    // }

    // return;
    var targetUrl = (target || 'http://127.0.0.1') + url.parse(req.url).path;

    var headers = {
      cookie: req.headers.cookie,
      accept: req.headers.accept,
      "content-type": req.headers['content-type']
    };

    var callback = function(error, response, body) {
      if (error) {
        logger.error('proxy to ' + targetUrl + ': ' + error);
        res.end(JSON.stringify({errCode: 300, message: targetUrl + ' connect error: ' + error}));
        return;
      }
      try {
        util.setHeaders(res, response.headers);
        res.end(body)
      } catch (e) {
        logger.error(e)
      }
    }

    if (req.method.toUpperCase() === "GET") {
      request.get({
        url: targetUrl,
        headers: headers
      }, callback);
    } else if (req.method.toUpperCase() === "POST") {
      //不知道为什么
      req.pipe(process.stdin);

      var form = new formidable.IncomingForm();
      form.parse(req, function(err, fields, files) {

        if (/^application\/json\b/.test(req.headers['content-type'])) {
          request.post({
            url: targetUrl,
            headers: headers,
            body: JSON.stringify(fields)
          }, callback);
        } else {
          request.post({
            url: targetUrl,
            headers: headers,
            form: fields
          }, callback);
        }
      });
    } else if (req.method.toUpperCase() === "PUT") {
      req.pipe(process.stdin);

      var form = new formidable.IncomingForm();
      form.parse(req, function(err, fields, files) {

        if (/^application\/json\b/.test(req.headers['content-type'])) {
          request.put({
            url: targetUrl,
            headers: headers,
            body: JSON.stringify(fields)
          }, callback);
        } else {
          request.put({
            url: targetUrl,
            headers: headers,
            form: fields
          }, callback);
        }
      });
    } else if (req.method.toUpperCase() === "DELETE") {
      request.delete({
        url: targetUrl,
        headers: headers
      }, callback);
    } else {
      logger.error('unknow request method');
      request[req.method.toLowerCase()]({
        url: targetUrl,
        headers: headers
      }, callback);
    }
  },
  paramLog: function(req, res) {
    if (req.method.toUpperCase() === "GET" || req.method.toUpperCase() === "DELETE") {
      logger.info(req.query)
    } else if (req.method.toUpperCase() === "PUT" || req.method.toUpperCase() === "POST") {
      req.pipe(process.stdin);

      var form = new formidable.IncomingForm();
      form.parse(req, function(err, fields, files) {
        logger.info(fields)
      })
    } else {
      logger.error('unknow request method');
    }
  },
  outJson: function(req, res, o) {
    res.setHeader('Content-Type', 'application/json; charset=utf-8');
    res.setHeader('Access-Control-Allow-Origin', '*');
    //res.setHeader('Access-Control-Allow-Headers', 'type');
    //res.setHeader('Access-Control-Max-Age', 3600 * 24 * 30);

    res.end(JSON.stringify(this.transformOutJson(o)));
  },
  transformOutJson: function(o) {
    // var result = {};
    // result.errCode = o.code || 200;
    // (o.msg ? result.message = o.msg : '');
    // (o.data ? result.data = o.data : '');
    // return result;
    return o;
  },
  outJsonp: function(req, res, o) {
    res.setHeader('Content-Type', 'text/javascript');
    var callback = req.query.callback;
    res.end(callback + "(" + JSON.stringify(this.transformOutJson(o)) + ")");
  },
  setHeaders: function(res, headers) {
    if (headers !== undefined) {
      for (var key in headers) {
        res.setHeader(key, headers[key]);
      }
    }
  }
}

module.exports = util;